맨위로가기

타입 클래스

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

타입 클래스는 특정 타입에 대해 함수 또는 상수 집합을 정의하는 기능으로, 주로 하스켈과 같은 함수형 프로그래밍 언어에서 사용된다. 타입 클래스를 통해 다형성을 구현하고, 코드의 유연성과 재사용성을 높일 수 있다. 타입 클래스는 타입 변수와 종류(Kind)를 가지며, 인스턴스 선언을 통해 특정 타입이 해당 타입 클래스의 요구 사항을 충족함을 나타낸다. C++20의 개념, Rust의 트레이트, Scala의 암시적 매개변수 등 다른 언어에서도 유사한 기능을 제공하며, 함수 종속성, 멀티 파라미터 타입 클래스, Coq 및 Agda의 타입 클래스 지원 등 다양한 관련 개념이 존재한다.

2. 타입 클래스의 기본

타입 클래스는 특정 클래스에 속하는 모든 타입에 대해 존재해야 하는 함수 또는 상수 이름의 집합과 해당 타입을 지정하여 정의된다.[5] 하스켈에서는 타입을 매개변수화할 수 있다.

프로그래머는 아래와 같이 `elem` 함수(요소가 목록에 있는지 확인하는 함수)를 정의할 수 있다.

```haskell

elem :: Eq a => a -> [a] -> Bool

elem y [] = False

elem y (x:xs) = (x == y) || elem y xs

```

`elem` 함수는 `a -> [a] -> Bool` 타입을 가지며, `Eq a`라는 문맥(context)을 갖는다. 여기서 `a`는 `Eq` 타입 클래스에 속하는 타입으로 제한된다. (하스켈에서 `=>`는 '클래스 제약'이라고 불린다.)

모든 타입 `t`는 주어진 타입 클래스 `C`의 모든 메서드 구현을 특정 타입 `t`에 대해 정의하는 ''인스턴스 선언''을 통해 `C`의 멤버가 될 수 있다. 예를 들어 새로운 데이터 타입 `t`가 정의되면, 타입 `t` 값에 대한 동등성 함수를 제공하여 이 새로운 타입을 `Eq`의 인스턴스로 만들 수 있다. 이 작업이 완료되면 `elem` 함수를 `[t]` (타입 `t`의 요소 목록)에 사용할 수 있다.

타입 클래스는 객체 지향 프로그래밍 언어의 클래스와는 다르다. 특히 `Eq`는 타입이 아니며, 타입 `Eq`의 '값'과 같은 것은 없다.

타입 클래스는 매개변수 다형성과 밀접하게 관련되어 있다. 예를 들어 위에 제시된 `elem` 함수의 타입에서 "`Eq a =>`" 타입 클래스 제약이 없다면, 매개변수 다형 타입 `a -> [a] -> Bool`이 된다.

2. 1. 타입 클래스 선언

타입 클래스는 클래스에 속하는 모든 타입에 대해 존재해야 하는 함수 또는 상수 이름 집합과 해당 타입을 지정하여 정의된다. 하스켈에서 타입은 매개변수화될 수 있다. 동일성을 허용하는 타입을 포함하도록 설계된 타입 클래스 `Eq`는 다음과 같은 방식으로 선언된다.

```haskell

class Eq a where

(==) :: a -> a -> Bool

(/=) :: a -> a -> Bool

```

여기서 `a`는 타입 클래스 `Eq`의 한 인스턴스이며, `a`는 두 개의 함수(동등성 및 부등식 함수)에 대한 함수 시그니처를 정의하며, 각 함수는 타입 `a`의 인수를 2개 받아 부울 값을 반환한다.

타입 변수 `a`는 kind *를 갖는다(*는 최신 Glasgow Haskell 컴파일러 (GHC) 릴리스에서 `Type`으로도 알려져 있다).[5] 즉 `Eq`의 kind는 다음과 같다.

```haskell

Eq :: Type -> Constraint

```

이 선언은 "타입 `a`가 타입 클래스 `Eq`에 속하려면, 해당 타입에 정의된 적절한 타입의 `(==)` 및 `(/=)`라는 함수가 있어야 한다"라고 읽을 수 있다.

2. 2. 타입 변수와 종류(Kind)

타입 클래스는 클래스에 속하는 모든 타입에 대해 존재해야 하는 함수 또는 상수 이름 집합과 해당 타입을 지정하여 정의된다. 하스켈에서 타입은 매개변수화될 수 있다. 동일성을 허용하는 타입을 포함하도록 설계된 타입 클래스 `Eq`는 다음과 같은 방식으로 선언된다.

```haskell

class Eq a where

(==) :: a -> a -> Bool

(/=) :: a -> a -> Bool

```

여기서 `a`는 타입 클래스 `Eq`의 한 인스턴스이며, `a`는 두 개의 함수(동등성 및 부등식 함수)에 대한 함수 시그니처를 정의하며, 각 함수는 타입 `a`의 인수를 2개 받아 부울 값을 반환한다.

타입 변수 `a`는 kind *를 가지며(*는 최신 GHC (글래스고 하스켈 컴파일러) 릴리스에서 `Type`으로도 알려져 있다),[5] 즉 `Eq`의 kind는 다음과 같다.

```haskell

Eq :: Type -> Constraint

```

이 선언은 "타입 `a`가 타입 클래스 `Eq`에 속하려면, 해당 타입에 정의된 적절한 타입의 `(==)` 및 `(/=)`라는 함수가 있어야 한다"라고 읽을 수 있다.

2. 3. 인스턴스 선언

하스켈에서 특정 타입이 타입 클래스의 인스턴스가 되려면 ''인스턴스 선언''을 사용해야 한다. 인스턴스 선언은 타입 클래스의 모든 메서드(함수 또는 상수) 구현을 특정 타입에 대해 정의하는 방식으로 이루어진다.

예를 들어, 새로운 데이터 타입 `t`를 정의하고 이 타입에 대한 동등성 함수를 제공하여 `Eq` 타입 클래스의 인스턴스로 만들 수 있다. 다음은 `Eq` 타입 클래스의 인스턴스 선언 예시이다.

```haskell

class Eq a where

(==) :: a -> a -> Bool

(/=) :: a -> a -> Bool

```

위 선언은 "타입 `a`가 타입 클래스 `Eq`에 속하려면, 해당 타입에 정의된 적절한 타입의 `(==)` 및 `(/=)`라는 함수가 있어야 한다"는 의미이다.

`Eq`의 인스턴스로 선언된 타입은 `elem` 함수와 같이 `Eq` 타입 클래스를 사용하는 함수에서 활용될 수 있다. `elem` 함수는 목록에 특정 요소가 있는지 확인하는 함수이며, 다음과 같이 정의된다.

```haskell

elem :: Eq a => a -> [a] -> Bool

elem y [] = False

elem y (x:xs) = (x == y) || elem y xs

```

`elem` 함수의 타입은 `a -> [a] -> Bool`이며, `Eq a`라는 문맥(context)을 가진다. 이는 `a`가 `Eq` 타입 클래스에 속하는 타입으로 제한됨을 의미한다.

타입 클래스는 객체 지향 프로그래밍 언어의 클래스와는 다르다. 특히, `Eq`는 타입이 아니며, 타입 `Eq`의 값과 같은 것은 존재하지 않는다.

타입 클래스는 매개변수 다형성과 관련이 있다. 예를 들어, `elem` 함수의 타입에서 `"Eq a =>"` 타입 클래스 제약이 없다면 매개변수 다형 타입 `a -> [a] -> Bool`이 된다.

3. Higher-kinded 다형성

타입 클래스는 kind가 `Type`인 타입 변수를 가질 필요는 없으며, 어떤 kind의 타입 변수든 가질 수 있다. 이러한 higher kind를 가진 타입 클래스는 때때로 생성자 클래스라고 불린다. (여기서 언급된 생성자는 `Just`와 같은 데이터 생성자가 아니라 `Maybe`와 같은 타입 생성자를 의미한다.) 예시는 `Monad` 클래스이다.[1]

```haskell

class Monad m where

return :: a -> m a

(>>=) :: m a -> (a -> m b) -> m b

```

`m`이 타입 변수에 적용된다는 것은 `Type -> Type` kind를 가지고 있음을 나타낸다. 즉, 타입을 받아 타입을 반환하며, `Monad`의 kind는 다음과 같다.[1]

```haskell

Monad :: (Type -> Type) -> Constraint

4. Multi-parameter 타입 클래스

타입 클래스는 여러 타입 매개변수를 허용하며, 이는 타입 간의 관계를 나타내는 데 사용될 수 있다.[6] 예를 들어, GHC 표준 라이브러리에서 `IArray` 클래스는 일반적인 불변 배열 인터페이스를 나타낸다. `IArray a e`라는 타입 클래스 제약 조건은 `a`가 `e` 타입의 요소를 가진 배열 타입임을 의미한다. 이러한 다형성 제한은 언박싱된 배열 타입을 구현하는 데 사용된다.

멀티메소드와 유사하게, 멀티 파라미터 타입 클래스는 여러 인수의 타입과 반환 타입에 따라 다른 메서드 구현을 호출할 수 있도록 지원한다. 멀티 파라미터 타입 클래스는 호출할 메서드를 런타임에 매번 검색할 필요가 없으며,[7] 대신, 호출할 메서드는 단일 파라미터 타입 클래스와 마찬가지로 컴파일되어 타입 클래스 인스턴스의 딕셔너리에 저장된다.

멀티 파라미터 타입 클래스를 사용하는 하스켈 코드는 하스켈 98 표준이 아니므로 이식성이 떨어진다. 그러나 GHC와 Hugs와 같이 널리 사용되는 하스켈 구현체는 멀티 파라미터 타입 클래스를 지원한다.

4. 1. 함수 종속성

Haskell에서 타입 클래스는 프로그래머가 타입 매개변수 간의 함수 종속성을 선언할 수 있도록 개선되었다. 이는 관계형 데이터베이스 이론에서 영감을 얻은 개념이다.[8][9] 타입 매개변수의 일부 하위 집합을 지정하면 나머지 타입 매개변수가 고유하게 결정된다고 프로그래머가 주장할 수 있다. 예를 들어, `s` 타입의 상태 매개변수를 갖는 일반적인 모나드 `m`은 타입 클래스 제약 조건 `Monad.State s m`을 만족한다. 이 제약 조건에는 함수 종속성 `m -> s`가 있다. 즉, `Monad.State` 타입 클래스의 주어진 모나드 `m`에 대해 `m`에서 접근할 수 있는 상태 타입은 고유하게 결정된다. 이는 컴파일러가 타입 추론을 수행하는 데 도움이 되며, 프로그래머가 타입 지향 프로그래밍을 수행하는 데에도 도움이 된다.

사이먼 페이턴 존스는 Haskell에 함수 종속성을 도입하는 것에 대해 복잡성을 이유로 반대했다.[10]

5. 타입 클래스와 암시적 매개변수

타입 클래스와 암시적 매개변수는 본질적으로 매우 유사하지만 완전히 동일하지는 않다. 타입 클래스 제약 조건이 있는 다형 함수는 직관적으로 타입 클래스의 인스턴스를 암시적으로 허용하는 함수로 취급될 수 있다. 인스턴스는 본질적으로 타입 클래스 인스턴스 정의를 포함하는 레코드이다. (이것이 실제로 Glasgow Haskell Compiler에서 타입 클래스가 내부적으로 구현되는 방식이다.)[11]

그러나 중요한 차이점이 있다. 암시적 매개변수는 더 ''유연''하여, 타입 클래스의 다른 인스턴스를 전달할 수 있다. 반대로 타입 클래스는 ''일관성'' 속성을 강제하며, 이는 주어진 타입에 대해 단 하나의 고유한 인스턴스 선택만 있어야 함을 의미한다. 일관성 속성은 타입 클래스를 다소 반모듈식으로 만들며, 이 때문에 오펀 인스턴스(클래스나 관심 있는 타입을 모두 포함하지 않는 모듈에서 정의된 인스턴스)는 강력히 권장되지 않는다. 그러나 일관성은 언어에 또 다른 수준의 안전성을 추가하여 동일한 코드의 두 개의 분리된 부분이 동일한 인스턴스를 공유한다는 보장을 제공한다.[11]

예를 들어, 정렬된 집합(`Set a` 타입)은 작동하기 위해 요소(`a` 타입)에 대한 전순서가 필요하다. 이는 요소에 대한 비교 연산자를 정의하는 제약 조건 `Ord a`로 입증될 수 있다. 그러나 전순서를 부과하는 방법은 여러 가지가 있을 수 있다. 집합 알고리즘은 일반적으로 집합이 구성된 후 정렬 변경에 관대하지 않으므로, 집합에서 작동하는 함수에 호환되지 않는 `Ord a`의 인스턴스를 전달하면 잘못된 결과(또는 충돌)가 발생할 수 있다. 따라서 이 특정 시나리오에서 `Ord a`의 일관성을 강제하는 것이 중요하다.

스칼라 타입 클래스의 인스턴스는 언어의 일반적인 값이다.[12][13] 이러한 인스턴스는 기본적으로 명시적으로 선언된 암시적 형식 매개변수에 대한 암시적 매개변수로 사용될 적절한 인스턴스를 범위 내에서 찾아 제공되지만, 일반적인 값이라는 것은 모호성을 해결하기 위해 명시적으로 제공될 수 있음을 의미한다. 결과적으로 스칼라 타입 클래스는 일관성 속성을 만족시키지 않으며 암시적 매개변수에 대한 구문적 설탕이다.

다음은 Cats 설명서에서 가져온 예시이다:[14]

```scala

// 텍스트 표현을 제공하는 타입 클래스

trait Show[A] {

def show(f: A): String

}

// 암시적 인스턴스가 있을 때만 작동하는 다형 함수

// Show[A] 사용 가능

def log[A](a: A)(implicit s: Show[A]) = println(s.show(a))

// String에 대한 인스턴스

implicit val stringShow = new Show[String] {

def show(s: String) = s

}

// 매개변수 stringShow는 컴파일러에 의해 삽입되었습니다.

scala> log("a string")

a string

5. 1. Coq와 Agda의 타입 클래스 지원

Coq (버전 8.2 이상)는 적절한 인스턴스를 추론하여 타입 클래스를 지원한다.[15] Agda 2의 최신 버전은 "인스턴스 인수"라는 유사한 기능을 제공한다.[16]

6. 연산자 오버로딩의 다른 접근 방식

표준 ML의 "동등성 타입" 메커니즘은 하스켈의 내장 타입 클래스 `Eq`와 유사하지만, 모든 동등성 연산자가 컴파일러에 의해 자동으로 파생된다는 차이점이 있다.[17] 프로그래머는 구조체 내에서 어떤 타입 구성 요소가 동등성 타입인지, 다형성 타입에서 어떤 타입 변수가 동등성 타입을 포함하는지를 지정하여 제어할 수 있다.

SMLOCaml의 모듈과 펑터는 하스켈의 타입 클래스와 비슷한 역할을 할 수 있다. 주요 차이점은 타입 추론의 역할이며, 이는 타입 클래스를 ''임시'' 다형성에 적합하게 만든다.[17] OCaml의 객체 지향 하위 집합은 타입 클래스와 비교할 수 있는 또 다른 접근 방식이다.

7. 관련 개념

GHC(Glasgow Haskell Compiler)에 구현된 오버로드된 데이터에 대한 유사한 개념은 타입 패밀리이다.[18]

Clean에서 타입 클래스는 Haskell과 유사하지만 약간 다른 구문을 가지고 있다.

Mercury는 타입 클래스를 가지고 있지만, Haskell의 그것과 정확히 같지는 않다.

증명 보조 도구 Coq는 최근 버전에서 타입 클래스를 지원한다. 일반적인 프로그래밍 언어와 달리, Coq에서 타입 클래스 정의 내에 명시된 타입 클래스의 모든 법칙(예: 모나드 법칙)은 각 타입 클래스 인스턴스에 대해 사용하기 전에 수학적으로 증명되어야 한다.

7. 1. C++20의 개념

C++20에서 개념(concept)을 사용하여 타입 클래스를 지원한다. 다음은 하스켈의 `Eq` 타입 클래스를 C++로 표현하는 예시이다.

```cpp

template

concept Eq = requires (T a, T b) {

{ a == b } -> std::convertible_to;

{ a != b } -> std::convertible_to;

};

```

이 코드는 `Eq`라는 개념을 정의하는데, 이 개념은 타입 `T`가 `==` 와 `!=` 연산자를 지원하고, 이 연산자들의 결과가 `bool` 타입으로 변환 가능해야 함을 나타낸다.

7. 2. Rust의 트레이트

Rust는 일관성을 가진 타입 클래스의 제한된 형태인 트레이트를 지원한다.[19]

7. 3. Scala의 타입 클래스

스칼라에서 타입 클래스의 인스턴스는 별개의 엔티티가 아닌 일반적인 값이다.[12][13] 이러한 인스턴스는 암시적 형식 매개변수에 대한 암시적 매개변수로 사용될 적절한 인스턴스를 찾아 제공되지만, 일반적인 값이라는 것은 모호성을 해결하기 위해 명시적으로 제공될 수 있음을 의미한다. 결과적으로 스칼라 타입 클래스는 일관성 속성을 만족시키지 않으며 암시적 매개변수에 대한 구문적 설탕이다.

다음은 Cats 설명서에서 가져온 예시이다:[14]

```scala

// 텍스트 표현을 제공하는 타입 클래스

trait Show[A] {

def show(f: A): String

}

// 암시적 인스턴스가 있을 때만 작동하는 다형 함수

// Show[A] 사용 가능

def log[A](a: A)(implicit s: Show[A]) = println(s.show(a))

// String에 대한 인스턴스

implicit val stringShow = new Show[String] {

def show(s: String) = s

}

// 매개변수 stringShow는 컴파일러에 의해 삽입되었습니다.

scala> log("a string")

a string

참조

[1] 학위논문 Type Classes and Instance Chains: A Relational Approach https://jgbm.github.[...] Department of Computer Science, Portland State University 2013
[2] 서적 Proceedings of the 16th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL '89) Association for Computing Machinery 1989
[3] 콘퍼런스 Parametric overloading in polymorphic programming languages 1988-03
[4] 서적 Programming Language Implementation and Logic Programming. PLILP 1991 Springer 1991
[5] 웹사이트 Type https://hackage.hask[...]
[6] 웹사이트 MultiParamTypeClasses http://prime.haskell[...]
[7] Youtube Into the Core - Squeezing Haskell into Nine Constructors https://www.youtube.[...] Simon Peyton-Jones 2016-09-14
[8] 서적 Programming Languages and Systems. ESOP 2000 Springer 2000
[9] 웹사이트 FunctionalDependencies http://prime.haskell[...]
[10] 웹사이트 MPTCs and functional dependencies https://mail.haskell[...] 2006
[11] AV media Type Classes vs. the World https://www.youtube.[...] Boston Haskell Meetup 2015-01-21
[12] 서적 Proceedings of the ACM International Conference on Object Oriented Programming Systems Languages and Applications (OOPSLA '10) Association for Computing Machinery 2010
[13] 웹사이트 The Neophyte's Guide to Scala Part 12: Type classes - Daniel Westheide http://danielwesthei[...]
[14] 웹사이트 Scala Cats http://typelevel.org[...]
[15] 웹사이트 A Gentle Introduction to Type Classes and Relations in Coq http://www.labri.fr/[...] 2014
[16] 웹사이트 Modelling Type Classes With Instance Arguments http://wiki.portal.c[...]
[17] 서적 Proceedings of the 34th Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL '07) http://citeseer.ist.[...] 2007
[18] 웹사이트 GHC/Type families - HaskellWiki http://www.haskell.o[...]
[19] 보고서 Specialization, coherence, and API evolution https://aturon.githu[...] 2017
[20] 서적 Proceedings of the 16th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL '89) Association for Computing Machinery 1989
[21] 콘퍼런스 Parametric overloading in polymorphic programming languages 1988-03
[22] 학위논문 Type Classes and Instance Chains: A Relational Approach https://jgbm.github.[...] Department of Computer Science, Portland State University 2013
[23] 서적 Programming Language Implementation and Logic Programming. PLILP 1991 Springer 1991
[24] 학위논문 Type Classes and Instance Chains: A Relational Approach https://jgbm.github.[...] Department of Computer Science, Portland State University 2013
[25] 서적 Proceedings of the 16th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL '89) Association for Computing Machinery 1989
[26] 콘퍼런스 Parametric overloading in polymorphic programming languages 1988-03
[27] 서적 Programming Language Implementation and Logic Programming. PLILP 1991 Springer 1991



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com